//	COPYRIGHT (C) 1980 BY BOARD OF TRUSTEES,
//	LELAND STANFORD JUNIOR UNIVERSITY

LET CYCLES(GSTARTND,GSTOPND,MAXCYCSIZE,CYCFUN,TREEFUN,BITCYCFUN) = VALOF
 $( STATIC $( EDGETOROOT = NIL; NEDGE = NIL; NFUNCYC = NIL; NEAM = NIL;
              FUNCYCS = NIL; NODE1 = NIL; NODE2 = NIL; EATCYC = NIL;
              CYC = NIL; CYCOPY = NIL; CYCSCR = NIL; CYCNODES = NIL;
              CYCMAX = NIL; GND = NIL; STACKLOC = NIL; NSW = NIL;
              ONSW = NIL; SPTR = NIL; ND1 = NIL; ND2 = NIL;
              FCYC = NIL; KEEPGOING = NIL; TFUN = NIL; EATBCYC = NIL $);

 LET CYCDFS(NODE,ANCEST) BE
  $( STATIC $( NBR = NIL $);
  LET ONBR,PTR,PTRTOP=0,CTSTART!NODE-1,CTSTOP!NODE;
  WHILE PTR<PTRTOP DO
   $(
   PTR:=PTR+1;
   NBR:=CTABLE!PTR;
   IF NBR=ONBR DO LOOP;
   ONBR:=NBR;
   IF NBR=ANCEST DO LOOP;
   IF EDGETOROOT!NBR=0 DO LOOP;
   STACKPTR:=STACKPTR+1;
   STACK!STACKPTR:=NODE;
   STACKPTR:=STACKPTR+1;
   STACK!STACKPTR:=-NBR;
   NEDGE:=NEDGE+1;
   NFUNCYC:=NFUNCYC+1
   $);
  ONBR:=0;
  PTR:=CTSTART!NODE-1;
  WHILE PTR<PTRTOP DO
   $(
   PTR:=PTR+1;
   NBR:=CTABLE!PTR;
   IF NBR=ONBR DO LOOP;
   ONBR:=NBR;
   IF EDGETOROOT!NBR NE 0 DO LOOP;
   STACKPTR:=STACKPTR+1;
   STACK!STACKPTR:=NODE;
   STACKPTR:=STACKPTR+1;
   STACK!STACKPTR:=NBR;
   NEDGE:=NEDGE+1;
   EDGETOROOT!NBR:=NEDGE;
   CYCDFS(NBR,NODE)
   $)
  $);

 LET MAKEELEMCYC() BE
  $( STATIC $( NODESLEFT = NIL; NEXTEDGE = NIL; STOPNODE = NIL $);

  LET WALKAROUND(NEXTNODE) BE
   IF NEXTNODE NE STOPNODE DO
    $(
    CYCNODES!NODESLEFT:=NEXTNODE;
    NEXTEDGE:=LOWELEM(INTERSECT(CYCSCR,NEAM!NEXTNODE,CYCOPY));
    IF SETSIZE(FLIPELEM(NEXTEDGE,CYCSCR))>0 DO RETURN;
    FLIPELEM(NEXTEDGE,CYCOPY);
    NODESLEFT:=NODESLEFT-1;
    TEST NODE1!NEXTEDGE=NEXTNODE THEN WALKAROUND(NODE2!NEXTEDGE)
    OR WALKAROUND(NODE1!NEXTEDGE)
    $);

  IF EATBCYC NE 0 DO UNLESS EATBCYC(CYC) DO $( KEEPGOING:=FALSE; RETURN $);
  NODESLEFT:=SETSIZE(CYC)
  IF [NODESLEFT>CYCMAX] BITOR [NODESLEFT=0] DO RETURN;
  NEXTEDGE:=LOWELEM(COPYSET(CYCOPY,CYC));
  FLIPELEM(NEXTEDGE,CYCOPY);
  STOPNODE:=NODE1!NEXTEDGE;
  CYCNODES!NODESLEFT:=STOPNODE;
  CYCNODES!0:=NODESLEFT;
  NODESLEFT:=NODESLEFT-1;
  WALKAROUND(NODE2!NEXTEDGE);
  IF NODESLEFT=0 DO
   $(
   NSETWDSM1:=ONSW;
   KEEPGOING:=EATCYC(CYCNODES);
   NSETWDSM1:=NSW
   $)
  $);

 LET PATHTOROOT(NODE) BE
  $( STATIC $( ETOR = NIL $);
  ETOR:=EDGETOROOT!NODE;
  IF ETOR=-1 DO RETURN;
  FLIPELEM(ETOR,FCYC);
  NODE:=NODE1!ETOR
  $) REPEAT;

 LET CYCMULT() BE
  TEST NFUNCYC=0 THEN MAKEELEMCYC()
  OR
   $( LET FCYC=FUNCYCS!NFUNCYC;
   NFUNCYC:=NFUNCYC-1;
   DUNDISJ(CYC,FCYC);
   CYCMULT();
   DUNDISJ(CYC,FCYC);
   IF KEEPGOING DO CYCMULT();
   NFUNCYC:=NFUNCYC+1
   $);

 EATCYC:=CYCFUN;
 TFUN:=TREEFUN;
 EATBCYC:=BITCYCFUN;
 CYCMAX:=MAXCYCSIZE;
 KEEPGOING:=TRUE;
 NEAM:=NEWVEC(GSTOPND-GSTARTND)-GSTARTND;
 EDGETOROOT:=NEWVEC(GSTOPND-GSTARTND)-GSTARTND;
 CYCNODES:=NEWVEC(GSTOPND-GSTARTND+1);
 GND:=GSTARTND;
 WHILE GND<GSTOPND DO $( GND:=GND+1; EDGETOROOT!GND:=0 $);
 EDGETOROOT!GSTARTND:=-1;
 NEDGE:=0;
 NFUNCYC:=0;
 STACKLOC:=STACKPTR;
 CYCDFS(GSTARTND,0);
 NODE1:=NEWVEC(NEDGE);
 NODE2:=NEWVEC(NEDGE);
 FUNCYCS:=NEWVEC(NFUNCYC);
 NSW:=NEDGE>>P2WDSZ;
 ONSW:=NSETWDSM1;
 NSETWDSM1:=NSW;
 GND:=GSTARTND-1;
 WHILE GND<GSTOPND DO
  $(
  GND:=GND+1;
  IF EDGETOROOT!GND NE 0 DO NEAM!GND:=ZEROSET(MAKESET())
  $);
 SPTR:=STACKLOC;
 NEDGE:=0;
 NFUNCYC:=0;
 WHILE SPTR<STACKPTR DO
  $(
  SPTR:=SPTR+1;
  ND1:=STACK!SPTR;
  SPTR:=SPTR+1;
  ND2:=STACK!SPTR;
  NEDGE:=NEDGE+1;
  IF ND2<0 DO
   $(
   ND2:=-ND2;
   NFUNCYC:=NFUNCYC+1;
   FCYC:=ZEROSET(MAKESET());
   FUNCYCS!NFUNCYC:=FCYC;
   FLIPELEM(NEDGE,FCYC);
   PATHTOROOT(ND1);
   PATHTOROOT(ND2)
   $);
  NODE1!NEDGE:=ND1;
  NODE2!NEDGE:=ND2;
  FLIPELEM(NEDGE,NEAM!ND1);
  FLIPELEM(NEDGE,NEAM!ND2)
  $);
 STACKPTR:=STACKLOC;
 CYC:=ZEROSET(MAKESET());
 CYCOPY:=MAKESET();
 CYCSCR:=MAKESET();
 TEST TFUN=0 THEN CYCMULT()
 OR TEST TFUN(EDGETOROOT,NODE1,NODE2) THEN CYCMULT() OR KEEPGOING:=FALSE;
 NSETWDSM1:=ONSW;
 FREESET(CYCSCR);
 FREESET(CYCOPY);
 FREESET(CYC);
 WHILE NFUNCYC>0 DO $( FREESET(FUNCYCS!NFUNCYC); NFUNCYC:=NFUNCYC-1 $);
 GND:=GSTOPND+1;
 WHILE GND>GSTARTND DO
  $(
  GND:=GND-1;
  IF EDGETOROOT!GND NE 0 DO FREESET(NEAM!GND)
  $);
 FREEVEC(FUNCYCS);
 FREEVEC(NODE2);
 FREEVEC(NODE1);
 FREEVEC(CYCNODES);
 FREEVEC(EDGETOROOT+GSTARTND);
 FREEVEC(NEAM+GSTARTND);
 RESULTIS KEEPGOING
 $);

LET LITTLECYCS(GSTART,GSTOP,CYCFUN) = VALOF
 $( STATIC $( C1 = [TABLE 1,0]; C2 = [TABLE 2,0,0]; GIX = NIL; CTPTR = NIL;
              PTRTOP = NIL; ONBR = NIL; NBR = NIL $);
 GIX:=GSTART-1;
 WHILE GIX<GSTOP DO
  $(
  GIX:=GIX+1;
  CTPTR:=CTSTART!GIX;
  PTRTOP:=CTSTOP!GIX;
  IF PTRTOP<CTPTR DO LOOP;
  IF NUMISBS!GIX NE 0 DO
   $(
   C1!1:=GIX;
   UNLESS CYCFUN(C1) DO RESULTIS FALSE
   $);
  C2!1:=GIX;
  C2!2:=0;
  ONBR:=CTABLE!CTPTR;
  WHILE CTPTR<PTRTOP DO
   $(
   CTPTR:=CTPTR+1;
   NBR:=CTABLE!CTPTR;
   IF NBR<GIX DO LOOP;
   TEST NBR=ONBR THEN
    IF C2!2 NE NBR DO $( C2!2:=NBR; UNLESS CYCFUN(C2) DO RESULTIS FALSE $)
   OR ONBR:=NBR
   $)
  $);
 RESULTIS TRUE
 $);

LET CYCSOK(GSTART,GSTOP,CMINS,CMAXS,DLISTS) = VALOF
 $( STATIC $( DIAMLISTS = NIL; CYCMINS = NIL; CYCMAXS = NIL; GRBRMAX = NIL;
              BRMAX = NIL; DEFSIZES = NIL; SZIX = NIL; IGNOREMINS = NIL $);

 LET CYCLEOK(CYCLE) = VALOF
  $( STATIC $( CYC = NIL; SIZE = NIL; SIZE0 = NIL; MAYBEBIGGER = NIL;
               NDIX = NIL; DIAMLIST = NIL $);

  LET SIZESCANNER(I) = VALOF
   TEST I=0 THEN RESULTIS [CYCMAXS!SIZE NE 0]
   OR
    $(
    LET DIAMLIST=DIAMLISTS![ATTYPE![CYC!I]];
    LET NDIAMS=DIAMLIST!0;
    WHILE NDIAMS>0 DO
     $(
     SIZE:=SIZE+DIAMLIST!NDIAMS;
     IF SIZE>BRMAX DO RESULTIS TRUE;
     IF SIZESCANNER(I-1) DO RESULTIS TRUE;
     SIZE:=SIZE-DIAMLIST!NDIAMS;
     NDIAMS:=NDIAMS-1
     $);
    RESULTIS FALSE
    $);

  CYC:=CYCLE;
  SIZE:=CYC!0;
  SIZE0:=SIZE;
  MAYBEBIGGER:=FALSE;
  NDIX:=0;
  WHILE NDIX<SIZE0 DO
   $(
   NDIX:=NDIX+1;
   DIAMLIST:=DIAMLISTS![ATTYPE![CYC!NDIX]]
   SIZE:=SIZE+DIAMLIST!1;
   IF SIZE>GRBRMAX DO RESULTIS TRUE;
   IF DIAMLIST!0>1 DO MAYBEBIGGER:=TRUE
   $);
  TEST MAYBEBIGGER THEN
   $(
   IF IGNOREMINS>SIZE DO IGNOREMINS:=SIZE;
   IF SIZE>BRMAX DO RESULTIS TRUE;
   SIZE:=SIZE0;
   RESULTIS SIZESCANNER(SIZE0)
   $)
  OR
   $(
   IF SIZE0<SIZE DO IF IGNOREMINS>SIZE DO IGNOREMINS:=SIZE;
   DEFSIZES!SIZE:=DEFSIZES!SIZE+1;
   RESULTIS [DEFSIZES!SIZE LE CYCMAXS!SIZE]
   $)
  $);

 DIAMLISTS:=DLISTS;
 CYCMINS:=CMINS;
 CYCMAXS:=CMAXS;
 GRBRMAX:=CYCMINS!0;
 DEFSIZES:=NEWVEC(GRBRMAX);
 SZIX:=0;
 BRMAX:=0;
 WHILE SZIX<GRBRMAX DO
  $(
  SZIX:=SZIX+1;
  DEFSIZES!SZIX:=0;
  IF CYCMAXS!SZIX=0 DO BRMAX:=SZIX
  $);
 IGNOREMINS:=GRBRMAX+1;
 UNLESS CYCLES(GSTART,GSTOP,GRBRMAX,CYCLEOK,0,0) DO
  $( FREEVEC(DEFSIZES); RESULTIS FALSE $);
 UNLESS LITTLECYCS(GSTART,GSTOP,CYCLEOK) DO
  $( FREEVEC(DEFSIZES); RESULTIS FALSE $);
 WHILE IGNOREMINS>2 DO
  $(
  IGNOREMINS:=IGNOREMINS-1;
  IF DEFSIZES!IGNOREMINS<CYCMINS!IGNOREMINS DO
   $( FREEVEC(DEFSIZES); RESULTIS FALSE $)
  $);
 FREEVEC(DEFSIZES);
 RESULTIS TRUE
 $);
